// Paketinė OS, II variantas
// Edmundas Drūteika
// Vytautas Bačiulis

class Interpretator {
    static boolean run(Machine machine, VirtualMachine VMachine) {
        int command = (int) VMachine.getCC();
        LongObject[] VMMemory = VMachine.getMemoryVM();

        int firstByte = (int) (VMMemory[command].getValue()/16777216L);
        int secondByte = (int) ((VMMemory[command].getValue()/65536L) % 256L);
        int thirdByte = (int) ((VMMemory[command].getValue() % 65536L)/256L);

        if (firstByte == 1) { // Registro AX duomenis nusiunčia į duomenų segmento tam tikrą adresą.
            if (notOutOfRange(secondByte, 127)) {
                VMMemory[128+secondByte].changeValue(VMachine.getAX());
                VMachine.changeCC(VMachine.getCC() + 1L);
                machine.changeCC(VMachine.getCC());
            } else {
                machine.changePI(1L);
            }
            return true;
        }
        else if (firstByte == 2) { // Registro BX duomenis nusiunčia į duomenų segmento tam tikrą adresą.
            if (notOutOfRange(secondByte, 127)) {
                VMMemory[128+secondByte].changeValue(VMachine.getBX());
                VMachine.changeCC(VMachine.getCC() + 1L);
                machine.changeCC(VMachine.getCC());
            } else {
                machine.changePI(1L);
            }
            return true;
        }
        else if (firstByte == 3) { // Duomenų segmento tam tikroje vietoje esantis žodis yra išsaugomas į registrą AX.
            if (notOutOfRange(secondByte, 127)) {
                VMachine.changeAX(VMMemory[128+secondByte].getValue());
                VMachine.changeCC(VMachine.getCC() + 1L);
                machine.changeCC(VMachine.getCC());
            } else {
                machine.changePI(1L);
            }
            return true;
        }
        else if (firstByte == 4) { // Duomenų segmento tam tikroje vietoje esantis žodis yra išsaugomas į registrą BX.
            if (notOutOfRange(secondByte, 127)) {
                VMachine.changeBX(VMMemory[128+secondByte].getValue());
                VMachine.changeCC(VMachine.getCC() + 1L);
                machine.changeCC(VMachine.getCC());
            } else {
                machine.changePI(1L);
            }
            return true;
        }
        else if (firstByte == 5) { // Registro AX duomenis nusiunčia į duomenų segmento adresą, saugomą BX registre.
            int address = (int) VMachine.getBX();

            if (notOutOfRange(address, 127)) {
                VMMemory[128+address].changeValue(VMachine.getAX());
                VMachine.changeCC(VMachine.getCC() + 1L);
                machine.changeCC(VMachine.getCC());
            } else {
                machine.changePI(1L);
            }
            return true;
        }
        else if (firstByte == 6) { // Registro BX duomenis nusiunčia į duomenų segmento adresą, saugomą AX registre.
            int address = (int) VMachine.getAX();

            if (notOutOfRange(address, 127)) {
                VMMemory[128+address].changeValue(VMachine.getBX());
                VMachine.changeCC(VMachine.getCC() + 1L);
                machine.changeCC(VMachine.getCC());
            } else {
                machine.changePI(1L);
            }
            return true;
        }
        else if (firstByte == 7) { // Duomenų segmento vietoje, saugomoje BX registre, esantis žodis yra išsaugomas į registrą AX.
            int address = (int) VMachine.getBX();

            if (notOutOfRange(address, 127)) {
                VMachine.changeAX(VMMemory[128+address].getValue());
                VMachine.changeCC(VMachine.getCC() + 1L);
                machine.changeCC(VMachine.getCC());
            } else {
                machine.changePI(1L);
            }
            return true;
        }
        else if (firstByte == 8) { // Duomenų segmento vietoje, saugomoje AX registre, esantis žodis yra išsaugomas į registrą BX.
            int address = (int) VMachine.getAX();

            if (notOutOfRange(address, 127)) {
                VMachine.changeBX(VMMemory[128+address].getValue());
                VMachine.changeCC(VMachine.getCC() + 1L);
                machine.changeCC(VMachine.getCC());
            } else {
                machine.changePI(1L);
            }
            return true;
        }
        else if (firstByte == 9) { // Sudeda AX ir BX registruose esančias reikšmes ir įrašo gautą rezultatą į registrą AX.
            VMachine.changeAX((VMachine.getAX() + VMachine.getBX()) % 4294967296L);
            VMachine.changeCC(VMachine.getCC() + 1L);
            machine.changeCC(VMachine.getCC());
            return true;
        }
        else if (firstByte == 10) { // Iš AX registre esančios reikšmės atimama BX registre esanti reikšmė ir gautas rezultatas išsaugomas į AX registrą.
            if (VMachine.getAX() >= VMachine.getBX()) {
                VMachine.changeAX(VMachine.getAX() - VMachine.getBX());
            } else {
                VMachine.changeAX(4294967297L-(VMachine.getBX() - VMachine.getAX()));
            }
            VMachine.changeCC(VMachine.getCC() + 1L);
            machine.changeCC(VMachine.getCC());
            return true;
        }
        else if (firstByte == 11) { // AX registre esanti reikšmė palyginama su BX registre esančia reikšme ir pagal tai keičiama SF registro reikšmė.
            long AXValue = VMachine.getAX();
            long BXValue = VMachine.getBX();

            if (AXValue == BXValue) {
                VMachine.changeSF(2L);
                machine.changeSF(2L);
            }
            else if (AXValue > BXValue) {
                VMachine.changeSF(0L);
                machine.changeSF(0L);
            } else {
                VMachine.changeSF(1L);
                machine.changeSF(1L);
            }
            VMachine.changeCC(VMachine.getCC() + 1L);
            machine.changeCC(VMachine.getCC());
            return true;
        }
        else if (firstByte == 12) { // Nesąlyginio valdymo perdavimo komanda.
            VMachine.changeCC((long) secondByte);
            machine.changeCC(VMachine.getCC());
            return true;
        }
        else if (firstByte == 13) { // JE.
            if (VMachine.getSF() == 2) {
                VMachine.changeCC((long) secondByte);
            } else {
                VMachine.changeCC(VMachine.getCC() + 1L);
            }
            machine.changeCC(VMachine.getCC());
            return true;
        }
        else if (firstByte == 14) { // JNE.
            if (VMachine.getSF() == 0 || VMachine.getSF() == 1) {
                VMachine.changeCC((long) secondByte);
            } else {
                VMachine.changeCC(VMachine.getCC() + 1L);
            }
            machine.changeCC(VMachine.getCC());
            return true;
        }
        else if (firstByte == 15) { // JA.
            if (VMachine.getSF() == 0) {
                VMachine.changeCC((long) secondByte);
            } else {
                VMachine.changeCC(VMachine.getCC() + 1L);
            }
            machine.changeCC(VMachine.getCC());
            return true;
        }
        else if (firstByte == 16) { // JB.
            if (VMachine.getSF() == 1) {
                VMachine.changeCC((long) secondByte);
            } else {
                VMachine.changeCC(VMachine.getCC() + 1L);
            }
            machine.changeCC(VMachine.getCC());
            return true;
        }
        else if (firstByte == 17) { // JEA.
            if (VMachine.getSF() == 2 || VMachine.getSF() == 0) {
                VMachine.changeCC((long) secondByte);
            } else {
                VMachine.changeCC(VMachine.getCC() + 1L);
            }
            machine.changeCC(VMachine.getCC());
            return true;
        }
        else if (firstByte == 18) { // JEB.
            if (VMachine.getSF() == 2 || VMachine.getSF() == 1) {
                VMachine.changeCC((long) secondByte);
            } else {
                VMachine.changeCC(VMachine.getCC() + 1L);
            }
            machine.changeCC(VMachine.getCC());
            return true;
        }
        else if (firstByte == 19) { // Nuskaito informaciją, esančią faile ir įrašo ją į duomenų segmentą nuo jo pradžios.
            if (secondByte == 0) { // Apsisaugome nuo Compiler bug'o (jis praleidžia parametrą 0, nors mes palaikome tik 1, 2 ir 3).
                machine.changePI(1L);
                return true;
            }

            if (secondByte == 1) { // Informacija nuskaitoma po žodį (kiekvienas simbolis dedamas į atitinkamą žodžio baitą).
                ReadWrite.readInput(machine, VMMemory, 1);
                if (machine.getPI() == 0 && machine.getIOI() == 0) {
                    VMachine.changeCC(VMachine.getCC() + 1L);
                    machine.changeCC(VMachine.getCC());
                }
                return true;
            }
            else if (secondByte == 2) { // Kiekvienas simbolis (įskaitant naujos eilutės simbolį) nuskaitomas į atskirą žodį.
                ReadWrite.readInput(machine, VMMemory, 2);
                if (machine.getPI() == 0 && machine.getIOI() == 0) {
                    VMachine.changeCC(VMachine.getCC() + 1L);
                    machine.changeCC(VMachine.getCC());
                }
                return true;
            }
            else if (secondByte == 3) { // Ženklais „ENTER“ atskirti skaičiai yra įrašomi į atskirus žodžius.
                ReadWrite.readInput(machine, VMMemory, 3);
                if (machine.getPI() == 0 && machine.getIOI() == 0) {
                    VMachine.changeCC(VMachine.getCC() + 1L);
                    machine.changeCC(VMachine.getCC());
                }
                return true;
            } else {
                System.out.println("\nKlaida! Nepalaikomas parametras.");
                System.out.println("Perduota reikšmė: " + secondByte + ".");
                return true;
            }
        }
        else if (firstByte == 20) { // Į failą išvedama informacija.
            if (thirdByte == 0) { // Apsisaugome nuo Compiler bug'o (jis praleidžia parametrą 0, nors mes palaikome tik 1, 2 ir 3).
                machine.changePI(1L);
                return true;
            }

            if (thirdByte == 1) { // Kiekvienas žodžio baitas yra įrašomas kaip simbolis pagal ASCII kodų lentelę.
                ReadWrite.writeOutput(machine, VMMemory, secondByte, 1);
                if (machine.getPI() == 0 && machine.getIOI() == 0) {
                    VMachine.changeCC(VMachine.getCC() + 1L);
                    machine.changeCC(VMachine.getCC());
                }
                return true;
            }
            else if (thirdByte == 2) { // Kiekvienas žodis yra įrašomas kaip simbolis pagal ASCII kodų lentelę.
                ReadWrite.writeOutput(machine, VMMemory, secondByte, 2);
                if (machine.getPI() == 0 && machine.getIOI() == 0) {
                    VMachine.changeCC(VMachine.getCC() + 1L);
                    machine.changeCC(VMachine.getCC());
                }
                return true;
            }
            else if (thirdByte == 3) { // Išvedami žodžiuose esantys skaičiai ir atskiriami ženklais „ENTER“.
                ReadWrite.writeOutput(machine, VMMemory, secondByte, 3);
                if (machine.getPI() == 0 && machine.getIOI() == 0) {
                    VMachine.changeCC(VMachine.getCC() + 1L);
                    machine.changeCC(VMachine.getCC());
                }
                return true;
            }
        }
        else if (firstByte == 21) {
            return false;
        }
        machine.changePI(1L);
        return true;
    }

    static boolean notOutOfRange(int value, int range) { // value must be decimal.
        if (value >= 0 && value <= range) {
            return true;
        } else {
            return false;
        }
    }
}